package com.example.assetmanagement.service.impl;

import com.example.assetmanagement.domain.Backup;
import com.example.assetmanagement.mapper.BackupMapper;
import com.example.assetmanagement.service.BackupService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@RequiredArgsConstructor
public class BackupServiceImpl implements BackupService {

    private final BackupMapper backupMapper;
    private final DataSource dataSource;

    @Value("${backup.dir:backups}")
    private String backupDir;

    @Value("${spring.datasource.username}")
    private String dbUser;
    @Value("${spring.datasource.password}")
    private String dbPwd;
    @Value("${spring.datasource.url}")
    private String dbUrl;

    private String getDatabaseName() {
        // jdbc:mysql://host:port/db?params
        int idx = dbUrl.lastIndexOf("/");
        String after = dbUrl.substring(idx + 1);
        int q = after.indexOf("?");
        return q > 0 ? after.substring(0, q) : after;
    }

    @Override
    @Transactional
    public void createBackup(Long userId) throws IOException, InterruptedException {
        Files.createDirectories(Paths.get(backupDir));
        String db = getDatabaseName();
        String fileName = db + "_" + System.currentTimeMillis() + ".sql";
        Path file = Paths.get(backupDir, fileName);
        String cmd = String.format("mysqldump -u%s -p%s %s -r %s", dbUser, dbPwd, db, file.toString());
        Process proc = Runtime.getRuntime().exec(cmd);
        int exit = proc.waitFor();
        if (exit != 0) throw new RuntimeException("mysqldump failed");
        Backup backup = new Backup();
        backup.setFilePath(file.toString());
        backup.setCreatedBy(userId);
        backup.setCreatedAt(LocalDateTime.now());
        backupMapper.insert(backup);
    }

    @Override
    @Transactional
    public void importBackup(MultipartFile sqlFile, Long userId) throws IOException, InterruptedException {
        Path tmp = Files.createTempFile("import", ".sql");
        sqlFile.transferTo(tmp);
        executeSqlFile(tmp);
        // 记录到备份表
        Backup b = new Backup();
        b.setFilePath(tmp.toString());
        b.setCreatedBy(userId);
        b.setCreatedAt(LocalDateTime.now());
        backupMapper.insert(b);
    }

    private void executeSqlFile(Path sql) throws IOException, InterruptedException {
        String db = getDatabaseName();
        String cmd = String.format("mysql -u%s -p%s %s < %s", dbUser, dbPwd, db, sql.toString());
        String[] fullCmd = {"bash", "-c", cmd};
        Process proc = Runtime.getRuntime().exec(fullCmd);
        int exit = proc.waitFor();
        if (exit != 0) throw new RuntimeException("mysql import failed");
    }

    @Override
    @Transactional
    public void restoreBackup(Long backupId) throws IOException, InterruptedException {
        Backup backup = backupMapper.selectById(backupId);
        if (backup == null) throw new RuntimeException("backup not found");
        executeSqlFile(Paths.get(backup.getFilePath()));
    }

    @Override
    @Transactional
    public void deleteBackup(Long backupId) {
        Backup backup = backupMapper.selectById(backupId);
        if (backup == null) return;
        FileUtils.deleteQuietly(new File(backup.getFilePath()));
        backupMapper.deleteById(backupId);
    }

    @Override
    public List<Map<String, Object>> list(int page, int size) {
        int offset = (page - 1) * size;
        List<Backup> list = backupMapper.selectPage(offset, size);
        return list.stream().map(b -> {
            Map<String, Object> m = new HashMap<>();
            m.put("id", b.getId());
            m.put("filePath", b.getFilePath());
            m.put("createdBy", b.getCreatedBy());
            m.put("createdAt", b.getCreatedAt());
            return m;
        }).toList();
    }

    @Override
    public long count() {
        return backupMapper.count();
    }
} 